package com.FrameWork.Common;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.FrameWork.Utils.Utils;

import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.StatFs;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;


public enum BitmapManager {
	INSTANCE;
	private final Map<String, SoftReference<Bitmap>> cache;
	public  static final ExecutorService pool= Executors.newFixedThreadPool(5);
	private Map<ImageView, String> imageMap = Collections
			.synchronizedMap(new WeakHashMap<ImageView, String>());
	private static int FREE_SD_SPACE_NEEDED_TO_CACHE = 1;
	private static int MB = 1024 * 1024;
	public static String DIR = Utils.DIR + "/" + Utils.ImageFolder;

	BitmapManager() {
		cache = new HashMap<String, SoftReference<Bitmap>>();

	}

	/**
	 * @param url
	 * @return
	 */
	public Bitmap getBitmapFromCache(String url) {
		if (cache.containsKey(url)) {
			return cache.get(url).get();
		}
		return null;
	}

	public void clearCache() {
		for (String key : cache.keySet()) {
			if (cache.get(key) != null) {
				Bitmap map = (cache.get(key).get());
				if (map != null)
					map.recycle();
				map = null;
			}
		}
	}



	public void loadBitmap(final String url, final ImageView imageView,int width,int height, ScaleType  type) {
		imageMap.put(imageView, url);
		String localUrl = URLEncoder.encode(url);
		if (Exist(localUrl))
		{
			Bitmap map = getResizedImage(DIR + "/" + localUrl,width,height);

			imageView.setImageBitmap(map);
			imageView.setScaleType(type);
			imageView.invalidate();
			cache.put(url, new SoftReference<Bitmap>(map));
		}
		else {
			queueJob(url, imageView,width,height,type);
		}
	}

	public void loadBitmap(final String url, final ImageView imageView,ScaleType type) {
		imageMap.put(imageView, url);
		Bitmap map = getLocalBitmap(url);
		if (null != map) {
			imageView.setImageBitmap(map);
			imageView.setScaleType(type);
			imageView.invalidate();
			cache.put(url, new SoftReference<Bitmap>(map));
		} else {
			queueJob(url, imageView,type);
		}
	}

	public void loadLocalBitmap(final String url, final ImageView imageView,int width,int height, ScaleType type) {
		//imageMap.put(imageView, url);
		if (!cache.containsKey(url) || cache.get(url).get() != null) {
			Bitmap bmp = getResizedImage(url, width,height);
			cache.put(url, new SoftReference<Bitmap>(bmp));
		} 

		imageView.setImageBitmap(cache.get(url).get());
		imageView.setScaleType(type);
		imageView.invalidate();

		//queueJob(url, imageView,width,height,type);


	}



	public void queueJob(final String url, final ImageView imageView,final ScaleType type) {
		final Handler handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				String tag = imageMap.get(imageView);
				if (tag != null && tag.equals(url)) {
					if (msg.obj != null) {
						imageView.setScaleType(type);
						imageView.setImageBitmap((Bitmap) msg.obj);
					}
				}
			}
		};
		pool.submit(new Runnable() {
			@Override
			public void run() {
				final Bitmap bmp = downloadBitmap(url);
				Message message = Message.obtain();
				message.obj = bmp;
				handler.sendMessage(message);
			}
		});
	}

	public void queueJob(final String url, final ImageView imageView,final int width,final int height,final ScaleType type) {
		new Handler().postDelayed(new Runnable() {
			@Override
			public void run() {
				Bitmap bmp = getResizedImage(url, width,height);
				imageView.setScaleType(type);
				imageView.setImageBitmap(bmp);
				cache.put(url, new SoftReference<Bitmap>(bmp));
			}
		}, 10);
		/*final Handler handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				String tag = imageMap.get(imageView);
				if (tag != null && tag.equals(url)) {
					Bitmap bmp = getResizedImage(url, width,height);
					imageView.setScaleType(type);
					imageView.setImageBitmap(bmp);
					cache.put(url, new SoftReference<Bitmap>(bmp));

				}
			}
		};

		pool.submit(	);*/
	}




	private Bitmap downloadBitmap(String url) {
		try {
			Bitmap bitmap = BitmapFactory.decodeStream((InputStream) new URL(
					url).getContent());
			cache.put(url, new SoftReference<Bitmap>(bitmap));
			saveBmpToSd(bitmap, URLEncoder.encode(url));
			return bitmap;
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return null;
	}

	public static boolean deleteImage(String url) {
		String localUrl = URLEncoder.encode(url);
		File file = new File(DIR + "/" + localUrl);
		if (file.exists())
			return file.delete();
		return false;
	}


	private static boolean Exist(String url) {
		return Utils.Exist(DIR + "/" + url);

	}


	public static Bitmap getLocalBitmap(String url) {
		String localUrl = URLEncoder.encode(url);
		if (Exist(localUrl))
			return BitmapFactory.decodeFile(DIR + "/" + localUrl);
		return null;
	}

	
	

	/**
	 * 
	 * @param imagePath
	 * @param maxWidth
	 * @param maxHeight
	 * @return
	 */
	public static Bitmap getResizedImage(String imagePath, int maxWidth,
			int maxHeight) {
		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		Bitmap bitmap = BitmapFactory.decodeFile(imagePath, options);
		options.inSampleSize = computeSampleSize(options, -1, maxWidth
				* maxHeight);
		options.inJustDecodeBounds = false;
		bitmap = BitmapFactory.decodeFile(imagePath, options);
		
		return bitmap;
	}
	
	
	



	public static int computeSampleSize(BitmapFactory.Options options,
			int minSideLength, int maxNumOfPixels) {
		int initialSize = computeInitialSampleSize(options, minSideLength,
				maxNumOfPixels);
		int roundedSize;
		if (initialSize <= 8) {
			roundedSize = 1;
			while (roundedSize < initialSize) {
				roundedSize <<= 1;
			}
		} else {
			roundedSize = (initialSize + 7) / 8 * 8;
		}
		return roundedSize;
	}

	private static int computeInitialSampleSize(BitmapFactory.Options options,
			int minSideLength, int maxNumOfPixels) {
		double w = options.outWidth;
		double h = options.outHeight;

		int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math
				.sqrt(w * h / maxNumOfPixels));
		int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math
				.floor(w / minSideLength), Math.floor(h / minSideLength));

		if (upperBound < lowerBound) {
			// return the larger one when there is no overlapping zone.
			return lowerBound;
		}

		if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
			return 1;
		} else if (minSideLength == -1) {
			return lowerBound;
		} else {
			return upperBound;
		}

	}

	/**
	 * ����sdcard�ϵ�ʣ��ռ�
	 * 
	 * @return
	 */
	private static int freeSpaceOnSd() {
		StatFs stat = new StatFs(Environment.getExternalStorageDirectory()
				.getPath());
		double sdFreeMB = ((double) stat.getAvailableBlocks() * (double) stat
				.getBlockSize())
				/ MB;

		return (int) sdFreeMB;
	}

	/**
	 * ����ͼƬ�����ػ���
	 * 
	 * @param bm
	 * @param url
	 */
	public static void saveBmpToSd(Bitmap bm, String url) {

		if (bm == null) {
			return;
		}
		if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
			return;
		}
		if (!Environment.MEDIA_MOUNTED.equals(Environment
				.getExternalStorageState()))
			return;
		String filename = url;
		File dirPath = new File(DIR);
		if (!dirPath.exists()) {
			dirPath.mkdir();
		}

		File file = new File(DIR + "/" + filename);
		try {
			if (file.exists())
				file.delete();
			file.createNewFile();
			OutputStream outStream = new FileOutputStream(file);
			bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
			outStream.flush();
			outStream.close();

		} catch (FileNotFoundException e) {

			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}